%code requires{
	#include "node.hpp"
	#include <vector>
}

%{
	#include "node.hpp"
	#include <stdio.h>
	#include <string>
	#include <sstream>
	#include <cctype>
	#include <fstream>

	int yylex(void);

	extern FILE * yyin;
	FILE * progo;

	NProgrammePrincipal* leprogramme;

	void yyerror(const char * msg) {printf( "erreur %s. \n",msg);}

	%}

/* DONNEES */
//valeurs pouvant etre retournées dans les $
	%union {
    //types
		std::string* stringT;
		int intT;
		float floatT;
		int token;
    //noeuds
		Node *node;
		NBlock *block;
		NArithmetique *arithmetique;
		NBoolean *boolean;
		NInstruction *instruction;
		NStatement* stmt;
		NProgramme* prog;
		NArgument* arg;
		NDeclaration* dec;

		programmedeclarationListe* pdecListe;
		arithmetiqueListe* ariListe;
		variableListe* varListe;
		statementsListe* stmtListe;
		argumentsdeclarationListe* argListe;
		declarationsListe* decListe;

	}

	%type <node> programme 
	%type <prog> programmedeclaration
	%type <arithmetique> arithmetique arithmetique_simple variable
	%type <boolean> booleene
	%type <instruction> instruction appelfonction
	%type <stmt> statement
	%type <arg> argumentdeclaration
	%type <dec> declaration

	%type <ariListe> listearithmetique
	%type <pdecListe> listeprogrammedeclaration programmedeclarations
	%type <varListe> listevariables
	%type <stmtListe> listestatements statements
	%type <argListe> listeargumentsdeclaration listeargumentsdeclarationvirgule
	%type <decListe> listedeclarations declarations

	%type <intT> unop binop comparateur
	%type <stringT> nomfonction typeT

//	LISTE DES TERMINAUX
	%token <stringT> N
	%token <stringT> D
	%token <stringT> X

	%left <intT> MOINS	
	%left <intT> MUL
	%left <intT> DIV 
	%left <intT> PLUS

	%left RT
	%left BG
%token <intT> INF SUP INFEGAL SUPEGAL EGAL DIFF 		/* Comparaisons <, >, <=, >=, =, <>*/
%token <intT> AFFECTATION 								/* Affectation */
	%token TRUE FALSE
%token PARENTHESEOUVRANTE PARENTHESEFERMANTE 	/* ( , ) */
%token CROCHETOUVRANT CROCHETFERMANT			/* [ , ] */
	%left <intT> NOT
	%left <intT> ET
	%left <intT> OU							
%token <intT> INT DECIMAL ARRAY							/* f */
%token <stringT> MOTFONCTION MOTPROCEDURE FREE NEW				/* fonction, procedure */
	%token IF THEN ELSE WHILE DO END
	%token IS VIRGULE POINTVIRGULE DEUXPOINTS 
	%start programme

	%%

programme ://ok
listeprogrammedeclaration statement
{
	leprogramme = new NProgrammePrincipal(*$1,*$2) ;
	//* car c'est des objets
	//dans le cas de lexels, (entiers), mettre juste $1
};

listeprogrammedeclaration ://ok
{
	$$ = new programmedeclarationListe(); 
	//printf("liste programme declaration vide\n");
}
| programmedeclarations
;

programmedeclarations ://ok
programmedeclaration
{
	$$ = new programmedeclarationListe();
	$$->push_back($1);
	//printf("programme declaration\n");
}
| programmedeclarations programmedeclaration 
{
	$1->push_back($2);
	$$ = $1;
	//printf("programme declarations\n");
}
;

programmedeclaration ://ok
MOTFONCTION nomfonction PARENTHESEOUVRANTE listeargumentsdeclaration PARENTHESEFERMANTE DEUXPOINTS typeT IS statement 
{
	$$ = new NFonction(*$2,*$4,*$7,*$9);
	//printf("fonction declarations\n");
}
| MOTPROCEDURE nomfonction PARENTHESEOUVRANTE listeargumentsdeclaration PARENTHESEFERMANTE IS statement
{
	$$ = new NProcedure(*$2,*$4,*$7);
	//printf("procedure declarations\n");
}
;

/* Operateur unaire */
unop ://ok
MOINS
;

/* Operateur binaire */
binop : //ok
PLUS
{
	$$ = 1;
}
| MOINS
{
	$$ = 2;
}
| MUL
{
	$$ = 3;
}
| DIV
{
	$$ = 4;
}
;

comparateur ://ok
INF
{
	$$ = 1;
}
| SUP
{
	$$ = 2;
}
| INFEGAL
{
	$$ = 3;
}
| SUPEGAL
{
	$$ = 4;
}
| EGAL
{
	$$ = 5;
}
| DIFF
{
	$$ = 6;
}
;

//A ::= n | d | x | x[A] | unop A | A binop A | (A)
/* Expression arythmetique */
arithmetique : //ok
arithmetique_simple
| unop arithmetique_simple
{
	$$ = new NUnop(*$2);
}
| arithmetique_simple binop arithmetique_simple 
{
	$$ = new NBinOp(*$1,$2,*$3);
}
;

arithmetique_simple: //ok
N
{
	int n = atoi($1->c_str());
	$$ = new NN(n);
}
| D
{
	float f = atof($1->c_str());
	$$ = new ND(f);
}
| variable
| PARENTHESEOUVRANTE arithmetique PARENTHESEFERMANTE
{
	$$ = $2;
}
;

/* Expressions booleennes */
//B ::= true | false | A cmp A | ! B | B && B | B || B | (B)
booleene ://ok
TRUE 
{
	$$ = new NTrue();
}
| FALSE
{
	$$ = new NFalse();
}
| arithmetique comparateur arithmetique
{
	$$ = new NCmp(*$1,$2,*$3);
}
| NOT booleene
{
	$$ = new NotBoolean(*$2);
}
| booleene ET booleene
{
	$$ = new NAnd(*$1,*$3);
}
| booleene OU booleene
{
	$$ = new NOr(*$1,*$3);
}
| PARENTHESEOUVRANTE booleene PARENTHESEFERMANTE
{
	$$ = $2;
}
;

/* lhs = nom de variable */
variable : //ok
X 
{
	$$ = new NVariable(*$1);
}
| X CROCHETOUVRANT arithmetique CROCHETFERMANT
{
	//$$ = new NArray(*$1,*$3);
	$$ = new NVariable(*$1);
}
;

nomfonction ://ok
X
;

typeT : //ok 
INT
{
	$$ = new string("int");
}
| DECIMAL
{
	$$ = new string("float");
}
| ARRAY PARENTHESEOUVRANTE typeT PARENTHESEFERMANTE
{
	$$ = new string("array "+*$3);
}
;

appelfonction:
nomfonction PARENTHESEOUVRANTE listearithmetique PARENTHESEFERMANTE
{
	$$ = new NAppelFonction(*$1,*$3);
}
;

/* Instruction */
instruction : 
RT POINTVIRGULE
{
	$$ = new NReturn();
}
| RT arithmetique POINTVIRGULE
{
	$$ = new NReturnValeur(*$2);
	//printf("return arithmetique\n");
}
| variable AFFECTATION arithmetique POINTVIRGULE
{
	$$ = new NAffectation(*$1,*$3);
	//printf("variable affectation\n");
}
| variable EGAL NEW typeT CROCHETOUVRANT arithmetique CROCHETFERMANT POINTVIRGULE
{
	$$ = new NNew(*$1,*$4,*$6);
}
| FREE PARENTHESEOUVRANTE arithmetique PARENTHESEFERMANTE POINTVIRGULE
{
	$$ = new NFree(*$3);
}
| appelfonction POINTVIRGULE
{
	$$ = $1;
}
| variable AFFECTATION appelfonction POINTVIRGULE
{
	$$ = new NEgalFonction(*$1,*$3);
}
;

statement : //ok
instruction 
{
	//printf("instruction\n");
}
| IF booleene THEN statement ELSE statement 
{
	$$ = new NIf(*$2,*$4,*$6);
	//printf("if then\n");
}
| WHILE booleene DO statement 
{
	$$ = new NWhile(*$2,*$4);
	//printf("while do\n");
}
| BG listedeclarations listestatements END 
{
	$$ = new NBlock(*$2,*$3);
	//printf("begin end\n");
}
;

listeargumentsdeclaration :
{
	$$ = new argumentsdeclarationListe();
	//printf("listelisteargumentsdeclaration vide\n");
}
| listeargumentsdeclarationvirgule
;

listeargumentsdeclarationvirgule :
argumentdeclaration
{
	$$ = new argumentsdeclarationListe();
	$$->push_back($1);
}
| listeargumentsdeclarationvirgule VIRGULE argumentdeclaration
{
	$1->push_back($3);
	$$ = $1;
};

argumentdeclaration :
variable DEUXPOINTS typeT
{
	$$ = new NArgument(*$1,*$3);
}
;


listearithmetique :
{
	$$ = new arithmetiqueListe();
	//printf("listelistearrithmetique vide\n");
}
| arithmetique
{
	$$ = new arithmetiqueListe();
	$$->push_back($1);
}
| listearithmetique VIRGULE arithmetique
{
	$1->push_back($3);
	$$ = $1;
}
;

listevariables://ok
variable
{
	$$ = new variableListe();
	$$->push_back($1);
}
| listevariables VIRGULE variable
{
	$1->push_back($3);
	$$ = $1;
}
;

/* vdecl = declaration */
declaration ://ok
typeT listevariables POINTVIRGULE
{
	$$ = new NDeclaration(*$1,*$2);
	//printf("declaration\n");
}
;

listedeclarations ://ok
{
	$$ = new declarationsListe();
	//printf("listedeclarations vide\n");
}
| declarations
;

declarations ://ok
declaration
{
	$$ = new declarationsListe();
	$$->push_back($1);
}
| declarations declaration
{
	$1->push_back($2);
	$$ = $1;
}

listestatements : //ok
{
	$$ = new statementsListe();
	//printf("listestatements vide\n");
}
| statements
;

statements://ok
statement
{
	$$ = new statementsListe(); 
	$$->push_back($1);
}
| statements statement
{
	$1->push_back($2);
	$$ = $1;
}
;

%%
int main(int argc, char ** argv) {
	printf("Début de l'analyse démantique\n\n");
	if (argc>1) yyin = fopen(argv[1],"r");
	//progo = fopen("prog.o","w");
	bool ok = yyparse();
	leprogramme->afficher();
	stringstream* ss = new stringstream();
	leprogramme->afficherMips(ss);
	ofstream fichierSortie("out.mips.txt",ios::out);
	fichierSortie<<ss->str();
	fichierSortie.close();
	if (!ok) return printf("\nAnalyse sémantique amorcée sans encombres !!!\n");
	return 1;
}

